筆記性質
建議搭配服用 : JS 執行環境
菜鳥初學,為了避免誤人子弟,請大神留步勘誤 QQ
先來個範例,猜猜結果為何?
var foo = 1;
function bar() {
console.log('bar First',foo)
if (!foo) { var foo = 10; }
console.log('bar Last',foo);
}
bar();
bar First: undefined
bar Last: 10
var foo = 1;
function bar() {
var foo; // 這裡改了
console.log('bar First',foo) // undefined
if (!foo) {
foo = 10; // 這裡改了
}
console.log('bar Last',foo); // 10
}
bar();
ES5 為 函數級作用域(function-level scope)
ES5 (var) Scope 切割單位為 Function
因此 ES5 需要用 IIFE 來產生區域的 scope
ES6 以 {} 做劃分,使用 let / const 即可 (Blocak-level scope)
Scope Chain 範圍鏈
找尋變量的過程,由內往外找,直到全域環境。
注意 若在 Function 內 沒有用 var 重新宣告,會產生全域變數
,進而變成改寫全域變數中的 myVar
Outer Environment 外部環境
當該執行環境找不到該變量時,會往外部環境做參照
要如何區分 Outer Environment (外部環境) : 看程式碼的相對位置
var myVar = 'Global'
function a() {
var myVar = 'Local'
function b() {
// b 的外層為 a()
console.log(myVar) // Local
}
return b
}
// c 的外層為 Global
function c() {
console.log(myVar) // Global
}
a()()
c()
var x = 1
if (true) {
var x = 2
let y = 2
console.log(x) // ? a
console.log(y) // ? b
}
console.log(x) // ? c
console.log(y) // ? d
Ans
a : 2 / b : 2 / c : 2 / d : y is not defined
ES5 var Scope 切割單位為 Function
因此 if else 中的 var x = 2 等同於 重新宣告了 x
foo() // foo is not a function
baz() // baz is not a function
bar() // 可用,函式宣告式,整塊被提升
function bar() = {}
var foo = function () {}; // 匿名函式表達式 (只有foo被提升)
var baz = function spam() { // 命名函式表達式 (只有baz被提升)
// spam 變數名稱 只可以用於此區塊
console.log(spam) // 指向此 Function
};
// Scope Chain 只可往外找,無法往內找
spam(); // ReferenceError "spam is not defined"
// IIFE 同 命名函式表達式 概念
;(function bzz() {
var inSide = 123
console.log(bzz) // 指向此 Function
}())
// IIFE 為 Function , Scope Chain 只可往外找,無法往內找
console.log(inSide) // inSide is not defined
console.log(bzz) // bzz is not defined
function b() {
console.log(myVar) // a
var myVar
console.log(myVar) // b
}
function a() {
var myVar = 2
b()
console.log(myVar) // c
function d() {
console.log(myVar) // d
}
d()
}
var myVar = 1
console.log(myVar) // e
a()
Ans
a : undefined / b : undefined / c : 2 / d : 2 / e : 1
a 因為 myVar 會在 b 中 hoisting 因此不會取到外部變數,
而是取到 var myVar; 的 undefined 值
ES5 Scope 切割單位為 Function
ES6 let const 為 Block Scope 因此只需要以 {} 劃分
使用 var 時,不論是否被執行,變數宣告皆會被提升至環境的最上方
Hoisting 於 建立 執行環境 的 建立階段 執行 (複習 JS 執行環境)
只會 Hoisting 宣告的部分,賦値仍要在執行階段執行。
函式宣告式 : 會 Hoisting 整塊程式碼,因此可於宣告前使用
函式表達式 : 只會提升宣告的部分,賦値仍要在執行階段執行。
andyyou
DavidShariff
PJChENder
ben cherry
感謝大大分享,第一次聽到 變數命名優先序
,
以前都以為是單純的後壓前,原來是有優先序的。
那個部分是我自己去測試的,有可能會漏掉一些細節順序,有抓到漏洞的話歡迎告知。
實際寫Code,當然是避免取相同變數為妙啦!
補充一下:
第一個例子裡的console.log('bar First',foo)
這個狀況,叫做Temporal Dead Zone,簡寫成TMZ。
感謝補充 ~
沒看過這個名詞,來去補補相關知識 QQ
簡寫好像是 TDZ?
阿,是TDZ....Orz
感謝版主賜教
var x = 1
if (true) {
var x = 2
let y = 2
console.log(x) // ? a
console.log(y) // ? b
}
console.log(x) // ? c
console.log(x) // d =>這邊是不是console.log(y)?
Ans
a : 2 / b : 2 / c : 1 / d : y is not defined
感謝勘誤 !
c 會是 2 因為 if 中 var x = 2 會重新宣告 全域變數 x
(ES5 var scope 最小範圍為 Function)